查看原文
其他

group_by和summrise连用后,分组计算就很方便。

果子 果子学生信 2023-06-15

关于分组计算这个话题,我在写过的那些帖子里面,经常用到的就是group_by联合summarise
比如多探针求最大值,多甲基化位点求平均值,TCGA中miRNA求最大值
GEO芯片中多个探针对应一个基因,是求平均值还是保留最大值?
批量读入TCGA的miRNA数据(注意细节)
R语言学习路上的忆苦思甜
凡是重复的,全部删掉,一个都不留!
从零开始学技能,以数据集合upset图为例。

group_by按照某一列把数据框分成多个组我是知道的,但是summarise我就比较疑惑了,因为他们家还有sammarise_all, 而且哪些函数能用在 summarise中,我也没有总结过,这次就准备来解决这个事情。

先来创建一个数据框来作练习。

set.seed(1119)
data <- data.frame(ID=rep(LETTERS,each=3),
                   sample1=sample(seq(10,1000),78),
                   sample2=sample(seq(10,100),78),
                   sample3=sample(seq(20,500),78))

其中set.seed(1119)是设定了一个随机种子,要保证大家跟我的结果一致

group_bysummarise都存在于dplyr这个包中,所以需要先加载R包。

library(dplyr)

然后我们来看一个最简单的运用,summarise中直接给n()来统计分组变量的频次

data %>%
  group_by(ID) %>% 
  summarise(n())
# A tibble: 26 x 2
   ID    `n()`
   <fct> <int>
 1 A         3
 2 B         3
 3 C         3
 4 D         3
 5 E         3
 6 F         3
 7 G         3
 8 H         3
 9 I         3
10 J         3

最终得到两列,统计了ID这一列数据出现的频次。这个功能跟我们的明星函数table一样

table(data$ID)
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 

在本次的sammarise中,我们用的是summarise(n())这种形式,所以结果中,第二列的列名是n(),我们可以通过赋值来改变列的名字,比如这样

data %>%
  group_by(ID) %>% 
  summarise(n=n())
# A tibble: 26 x 2
   ID        n
   <fct> <int>
 1 A         3
 2 B         3
 3 C         3
 4 D         3
 5 E         3
 6 F         3
 7 G         3
 8 H         3
 9 I         3
10 J         3

好了,记住这个写法就行了。下面我们扩展一下。直接给n()函数,他统计的是分组的频次,如果我想计算的是分组后,每个小组内部的信息怎么办,比如求第一列的最大值就可以这样做。

data %>%
  group_by(ID) %>% 
  summarise(sample1=max(sample1))
# A tibble: 26 x 2
   ID    sample1
   <fct>   <int>
 1 A         990
 2 B         759
 3 C         752
 4 D         872
 5 E         672
 6 F         905
 7 G         649
 8 H         918
 9 I         579
10 J         611

还可以用summarise_at函数这样做,对比一下差异。

data %>%
  group_by(ID) %>% 
  summarise_at("sample1",max)

那么summarise中除了,n()max()函数,还能放哪些呢。
简单的说,只要是能够对向量起作用的函数,都可以放在里面,比如。

mean(): the mean AKA the average
sd(): the standard deviation, which is a measure of spread
min() and max(): the minimum and maximum values respectively
IQR(): Interquartile range
sum(): the sum
n(): a count of the number of rows/observations in each group

这段话是来自于一个网上教程,叫,R数据处理。
https://cengel.github.io/R-data-wrangling/
现在我们要拓展一下了
summarise可以作用于多个列,比如

data %>%
  group_by(ID) %>% 
  summarise(sample1=max(sample1),
            sample2=max(sample2))
# A tibble: 26 x 3
   ID    sample1 sample2
   <fct>   <int>   <int>
 1 A         990      84
 2 B         759      89
 3 C         752      95
 4 D         872      93
 5 E         672      79
 6 F         905      91
 7 G         649      78
 8 H         918      48
 9 I         579      80
10 J         611      94

也可以用summarise_at函数这样做,对比一下差异。

data %>%
  group_by(ID) %>% 
  summarise_at(c("sample1","sample2"),max)

再拓展一下,内部的函数可以不一样,一个求最大值,一个求最小值

data %>%
  group_by(ID) %>% 
  summarise(sample1=max(sample1),
            sample2=min(sample2))
# A tibble: 26 x 3
   ID    sample1 sample2
   <fct>   <int>   <int>
 1 A         990      33
 2 B         759      26
 3 C         752      19
 4 D         872      54
 5 E         672      30
 6 F         905      37
 7 G         649      10
 8 H         918      12
 9 I         579      66
10 J         611      17

只要你有闲心,你甚至可以把每一列都操作一下

data %>%
  group_by(ID) %>% 
  summarise(sample1=max(sample1),
            sample2=max(sample2),
            sample3=max(sample3))

summarise_at函数也是可以的。

data %>%
  group_by(ID) %>% 
  summarise_at(c("sample1","sample2","sample3"),max)

假如像上面一样,每一个函数都是一样的,那么就可以用summarise_all
因为这个是对全部列起作用,所以函数内部可以不用写参数。

data %>%
  group_by(ID) %>% 
  summarise_all(max)
# A tibble: 26 x 4
   ID    sample1 sample2 sample3
   <fct>   <int>   <int>   <int>
 1 A         990      84     443
 2 B         759      89     181
 3 C         752      95     413
 4 D         872      93     287
 5 E         672      79     471
 6 F         905      91     371
 7 G         649      78     491
 8 H         918      48     476
 9 I         579      80     484
10 J         611      94     392

刚才是求最大值,现在尝试求平均值试试

data %>%
  group_by(ID) %>% 
  summarise_all(mean)
A tibble: 26 x 4
   ID    sample1 sample2 sample3
   <fct>   <dbl>   <dbl>   <dbl>
 1 A        663.    53.7    261.
 2 B        521     54.7    124.
 3 C        476.    47.3    334 
 4 D        442.    74.3    257.
 5 E        554     49.7    411 
 6 F        671.    56.3    222.
 7 G        345.    50.3    397.
 8 H        638.    35.3    259.
 9 I        474.    72.3    316 
10 J        323.    61.3    298 

这一招用在甲基化位点和基因的对应关系那里很有用,比如,多个甲基化位点对应一个基因,我们可以用这里的方法选取最大值,最小值,或者平均值。
当然,我们想要一次性施加多个函数,也是可以的,这样写就行

data %>%
  group_by(ID) %>% 
  summarise_all(list(max,min,mean))
# A tibble: 26 x 10
   ID    sample1_fn1 sample2_fn1 sample3_fn1 sample1_fn2 sample2_fn2 sample3_fn2 sample1_fn3 sample2_fn3 sample3_fn3
   <fct>       <int>       <int>       <int>       <int>       <int>       <int>       <dbl>       <dbl>       <dbl>
 1 A             990          84         443         405          33          53        663.        53.7        261.
 2 B             759          89         181         130          26          94        521         54.7        124.
 3 C             752          95         413          47          19         233        476.        47.3        334 
 4 D             872          93         287          57          54         232        442.        74.3        257.
 5 E             672          79         471         346          30         326        554         49.7        411 
 6 F             905          91         371         268          37          69        671.        56.3        222.
 7 G             649          78         491          89          10         278        345.        50.3        397.
 8 H             918          48         476         206          12          25        638.        35.3        259.
 9 I             579          80         484         349          66          71        474.        72.3        316 
10 J             611          94         392          49          17         237        323.        61.3        298 

计算的结果,按照函数出现的顺序,依次排列。不过,看得有点混乱,我们可以通过赋值变量来改善一下

data %>%
  group_by(ID) %>% 
  summarise_all(list(max = max,min = min,mean = mean))

这样通过列名就可以看得很清楚

# A tibble: 26 x 10
   ID    sample1_max sample2_max sample3_max sample1_min sample2_min sample3_min sample1_mean sample2_mean sample3_mean
   <fct>       <int>       <int>       <int>       <int>       <int>       <int>        <dbl>        <dbl>        <dbl>
 1 A             990          84         443         405          33          53         663.         53.7         261.
 2 B             759          89         181         130          26          94         521          54.7         124.
 3 C             752          95         413          47          19         233         476.         47.3         334 
 4 D             872          93         287          57          54         232         442.         74.3         257.
 5 E             672          79         471         346          30         326         554          49.7         411 
 6 F             905          91         371         268          37          69         671.         56.3         222.
 7 G             649          78         491          89          10         278         345.         50.3         397.
 8 H             918          48         476         206          12          25         638.         35.3         259.
 9 I             579          80         484         349          66          71         474.         72.3         316 
10 J             611          94         392          49          17         237         323.         61.3         298 

这样,我们就介绍完了summarise,summarise_at,summarise_all,而且也知道了内部使用的函数有哪些。
但是还有一个问题,如果数据比较多,但是有一些列不能被施加函数,怎么办呢。土方法就是,用summarise或者summarise_at一一指定,但是数据多的话太麻烦了,有没有什么好方法呢,有。

我们重新创建一个测试数据

data <- data.frame(ID=rep(LETTERS,each=3),
                   sample1=sample(seq(10,1000),78),
                   sample2=sample(seq(10,100),78),
                   sample3=sample(letters,78,replace = T))

这个数据的有一列不是数字,是字母,如果我想分组对所有列求和怎么办?通常的写法是这样的

data %>%
  group_by(ID) %>% 
  summarise_all(max)

会报错的

Error in Summary.factor(c(4L, 5L, 2L), na.rm = FALSE) : 
  ‘max’ not meaningful for factors

此时我们可以用另外一个函数summarise_if来判断,是数值的计算,不是数值的就不要

data %>%
  group_by(ID) %>% 
  summarise_if(is.numeric,max)
# A tibble: 26 x 3
   ID    sample1 sample2
   <fct>   <int>   <int>
 1 A         681      89
 2 B         831      61
 3 C         616      97
 4 D         915      29
 5 E         807      55
 6 F         500      98
 7 G         822      67
 8 H         804      94
 9 I         871     100
10 J         876      83

这样group_by联合summarise的用法就讲完了,实战运用请参考文章开头的几个帖子。
我们后面要讲一讲,gatherspread,以及他们是如何遭遗弃的故事。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存